from flask import Flask, request, jsonify, send_from_directory from flask_cors import CORS import os import json from datetime import datetime app = Flask(__name__) CORS(app) # Enable CORS for all routes ########### status open/close ########### # # File to persist locker statuses # LOCKERS_FILE = "lockers_status.json" # # Load existing statuses from file (if available) # if os.path.exists(LOCKERS_FILE): # with open(LOCKERS_FILE, "r") as file: # lockers_status = json.load(file) # else: # # Initialize lockers status (7 lockers, all closed initially) # lockers_status = { # "a": 0, # "b": 0, # "c": 0, # "d": 0, # "e": 0, # "f": 0, # "g": 0 # } @app.route('/update_locker', methods=['POST']) def update_locker(): """ Updates the status of a specific locker. Expects a JSON payload with "locker_id" and "status". """ LOCKERS_DATA_FILE = "lockers_data.json" # Load existing lockers data if os.path.exists(LOCKERS_DATA_FILE): with open(LOCKERS_DATA_FILE, "r") as file: locker_data = json.load(file) else: return jsonify({"error": "Locker data file not found!"}), 404 # Parse the incoming JSON payload data = request.get_json() if not data or "locker_id" not in data or "status" not in data: return jsonify({"error": "Invalid request, must include 'locker_id' and 'status'"}), 400 locker_id = data["locker_id"] status = data["status"] # Validate locker ID and status locker = next((l for l in locker_data if l["id"] == locker_id), None) if not locker: return jsonify({"error": f"Locker ID {locker_id} is invalid"}), 400 if status not in [0, 1]: return jsonify({"error": f"Status {status} is invalid, must be 0 or 1"}), 400 # Update the locker status locker["status"] = status # Save the updated data back to the JSON file with open(LOCKERS_DATA_FILE, "w") as file: json.dump(locker_data, file, indent=4) return jsonify({"message": f"Locker {locker_id} updated to {status}", "current_data": locker_data}) ########### update code_open ########### @app.route('/set_open_code', methods=['POST']) def set_open_code(): """ sends the new code from the frontend to the json in the backend """ data = request.get_json() if not data or "locker_id" not in data or "new_code" not in data: return jsonify({"error": "Invalid request, must include 'locker_id' and 'new_code'"}), 400 locker_id = str(data["locker_id"]) new_code = str(data["new_code"]) # Validate that new_code is exactly 4 digits if len(new_code) != 4 or not new_code.isdigit(): return jsonify({"error": "Code must be exactly 4 numeric digits"}), 400 LOCKERS_DATA_FILE = "lockers_data.json" if not os.path.exists(LOCKERS_DATA_FILE): return jsonify({"error": "lockers_data.json not found"}), 404 # Load existing lockers data with open(LOCKERS_DATA_FILE, "r") as file: locker_data = json.load(file) # Find the locker by ID locker = next((l for l in locker_data if l["id"] == locker_id), None) if not locker: return jsonify({"error": f"Locker ID {locker_id} not found"}), 400 # Update the open_code locker["open_code"] = new_code # Save the updated data back with open(LOCKERS_DATA_FILE, "w") as file: json.dump(locker_data, file, indent=4) return jsonify({"message": f"open_code for locker {locker_id} updated to {new_code}"}), 200 @app.route('/get_open_code', methods=['GET']) def get_open_code(): """ endpoint for the Xiao to retrieve new code. """ locker_id = request.args.get("locker_id") if not locker_id: return jsonify({"error": "Must provide locker_id as query parameter"}), 400 LOCKERS_DATA_FILE = "lockers_data.json" if not os.path.exists(LOCKERS_DATA_FILE): return jsonify({"error": "lockers_data.json not found"}), 404 with open(LOCKERS_DATA_FILE, "r") as file: locker_data = json.load(file) # Find the locker by ID locker = next((l for l in locker_data if l["id"] == locker_id), None) if not locker: return jsonify({"error": f"Locker ID {locker_id} not found"}), 400 code = locker.get("open_code", None) if code is None: return jsonify({"error": f"No open_code found for locker {locker_id}"}), 404 return jsonify({"locker_id": locker_id, "open_code": code}) # @app.route('/update_locker', methods=['POST']) # def update_locker(): # """ # Updates the status of a specific locker. # Expects a JSON payload with "locker_id" and "status". # """ # # File to persist locker statuses # LOCKERS_FILE = "lockers_status.json" # # Load existing statuses from file (if available) # if os.path.exists(LOCKERS_FILE): # with open(LOCKERS_FILE, "r") as file: # lockers_status = json.load(file) # # Log the raw request data # print("Raw request data:", request.data.decode('utf-8')) # # Parse the incoming JSON payload # data = request.get_json() # # Log the parsed JSON payload # print("Parsed JSON payload:", data) # if not data or "locker_id" not in data or "status" not in data: # return jsonify({"error": "Invalid request, must include 'locker_id' and 'status'"}), 400 # locker_id = data["locker_id"] # status = data["status"] # # Validate locker ID and status # locker_id = str(locker_id) # if locker_id not in lockers_status: # print(f"Invalid locker_id received: {locker_id}, while lockers_status is {lockers_status}") # return jsonify({"error": f"Locker ID {locker_id} is invalid, while lockers_status is {lockers_status}"}), 400 # if status not in [0, 1]: # print(f"Invalid status received: {status}") # return jsonify({"error": f"Status {status} is invalid, must be 0 or 1"}), 400 # # Update status # lockers_status[locker_id] = int(status) # # Save to file # with open(LOCKERS_FILE, "w") as file: # json.dump(lockers_status, file) # print(f"Locker {locker_id} updated to {status}. Current status: {lockers_status}") # return jsonify({"message": f"Locker {locker_id} updated to {status}", "current_status": lockers_status}) # # Route to serve the lockers_status.json file # @app.route('/lockers_status') # def serve_lockers_status(): # return send_from_directory('.', 'lockers_status.json') @app.route('/lockers', methods=['GET']) def get_lockers(): """ Returns a list of locker data, including their metadata and status. """ LOCKERS_DATA_FILE = "lockers_data.json" # Load locker data from the JSON file if os.path.exists(LOCKERS_DATA_FILE): with open(LOCKERS_DATA_FILE, "r") as file: lockers_data = json.load(file) for locker in lockers_data: locker['image'] = f"http://127.0.0.1:5000/{locker['image']}" else: return jsonify({"error": "Locker data file not found!"}), 404 return jsonify(lockers_data) # Route to serve static files IMAGE_FOLDER = "images" @app.route('/images/') def serve_image(filename): print(f"Requested file: {filename}") return send_from_directory(IMAGE_FOLDER, filename) @app.route('/lockers/', methods=['GET']) def get_locker(locker_id): locker = next((locker for locker in lockers if locker["id"] == locker_id), None) if locker: return jsonify(locker) else: return jsonify({"error": "Locker not found"}), 404 ########### images ########### # Directory to store uploaded images UPLOAD_FOLDER = './uploads' os.makedirs(UPLOAD_FOLDER, exist_ok=True) @app.route('/') def home(): return "Hello, Flask is running!" # Route to handle image uploads from ESP32 @app.route('/uploads', methods=['POST']) def upload_image(): if 'image' not in request.files: return jsonify({'status': 'error', 'message': 'No image file found!'}), 400 image = request.files['image'] image_path = os.path.join(UPLOAD_FOLDER, image.filename) image.save(image_path) print(f"Image saved at {image_path}") return jsonify({'status': 'success', 'message': 'Image uploaded successfully!'}), 200 # New route to serve uploaded images @app.route('/uploads/', methods=['GET']) def get_image(filename): return send_from_directory(UPLOAD_FOLDER, filename) if __name__ == '__main__': import os # port = int(os.environ.get("PORT", 4000)) # Default to 4000 for local testing app.run(host='0.0.0.0', port=8080)